/**
 * 
 */
package homework2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * This is my solution to the HW#2 question#4
 * 
 * for each point i in the plane:
 *  for each point j in the plane:
 *        if i!=j,
 *           Compute and store the slope
 *  Sort the slope array
 *  Count similar slopes
 *  Increment the max number
 * Output the max number
 * 
 * @author David Everitt
 * @version HW#2 Problem4
 */
public class Point {
	private int x; // x-axis
	private int y; // y-axis
	
	/**
	 * Getter for the x-coordinate of a point
	 * @return x-coordinate
	 */
	public int getX() {
		return x;
	}

	/**
	 * Getter for y-coordinate of a point
	 * @return y-coordinate
	 */
	public int getY() {
		return y;
	}
	/**
	 * Default Point constructor
	 */
	public Point() {
		this.x = 0;
		this.y = 0;
	}

	/**
	 * Point constructor with coordinates
	 * @param a
	 * @param b
	 */
	public Point(int a, int b) {
		this.x = a;
		this.y = b;
	}

	/**
	 * Driver method for points program.
	 * @param args not used in this class
	 */
	public static void main(String[] args) {
		Point main = new Point();
		Point[] points = new Point[20];
		points[0] = new Point(0, -5);
		points[1] = new Point(-1, -3);
		points[2] = new Point(-2, -1);
		points[3] = new Point(1, 1);
		points[4] = new Point(-3, 1);
		points[5] = new Point(15, -10);
		points[6] = new Point(-20, 0);
		points[7] = new Point(8, -19);
		points[8] = new Point(-5, 15);
		points[9] = new Point(4, -8);
		points[10] = new Point(-10, 15);
		points[11] = new Point(-1, 2);
		points[12] = new Point(4, -10);
		points[13] = new Point(7, -18);
		points[14] = new Point(3, 3);
		points[15] = new Point(4, -15);
		points[16] = new Point(0, 10);
		points[17] = new Point(0, 20);
		points[18] = new Point(0, -10);
		points[19] = new Point(0, -20);
		System.out.println(main.maxNumPoints(points));
	}

	/**
	 * Calculates the maximum number of points on a 2 dimensional line
	 * 
	 * @param inputs Array of points
	 * @return Maximum points on any given line
	 */
	public int maxNumPoints(Point[] inputs) {
		int numPoints = inputs.length;
		int maxPoints = 0;
		if (numPoints < 3) {
			return numPoints;
		}
		List<Double> slopes = new ArrayList<Double>();
		for (int i = 0; i < numPoints; i++) {
			slopes.clear();
			int duplicates = 1;
			innerLoop(inputs, slopes, duplicates, i);
			Collections.sort(slopes);
			int points = 1;
			if (slopes.size() == 0) {
				points = 0;
			} else {
				points = 1;
			}
			// count equal slopes from point
			for (int k = 1; k < slopes.size(); k++) {
				if (slopes.get(k).equals(slopes.get(k- 1))) {
					points++;
				} else {
					points = 1;
				}
			}
			if (points + duplicates > maxPoints) {
				maxPoints = points + duplicates;
			}
		}
		return maxPoints;
	}

	/**
	 * Process slopes and duplicates on each point from origin
	 * 
	 * @param inputs Original array of Points
	 * @param slopes Array of slopes
	 * @param duplicates Counter for duplicates
	 * @param i Point of origin
	 */
	private void innerLoop(Point[] inputs, List<Double> slopes, int duplicates, int i) {
		int numPoints = inputs.length;
		for (int j = 0; j < numPoints; j++) {
			if (i != j) {
				if (inputs[i].getX() - inputs[j].getX() == 0) {
					if (inputs[i].getY() - inputs[j].getY() == 0) {
						duplicates++;
					} else {
						slopes.add(Double.MAX_VALUE);
					}
				} else {
					slopes.add((double) ((inputs[i].getY() - inputs[j].getY()) / 
							((inputs[i].getX() - inputs[j].getX()))));
				}
			}
		}
	}

}
